<template>
  <div class="goods-sku" v-if="specs">
      <dl v-for="(item, key) in list" :key="key">
          <dt>{{ item.name }}</dt>
          <dd>
              <template v-for="(it, k) in item.values">
                  <span v-if="it.picture == null" :key="it.name"
                      :class="{ selected: it.selected, disabled: it.disabled }" @click="select(key, k)">{{ it.name
                      }}</span>
                  <img :src="it.picture" v-if="it.picture" :key="it.name"
                      :class="{ selected: it.selected, disabled: it.disabled }" @click="select(key, k)" />
              </template>
          </dd>
      </dl>
  </div>
</template>
<script>
// 最后一步 当所有的规格选择完毕后 需要将数据传递给父组件
// 1.什么算选择完毕 选择值的数组和specs的长度一样的时候 2.传出什么 传规格id oldPrice price name 

//当用户点击的时候判断是否需要有禁用元素的思路
//首先定义一个方法  在点击按钮的时候会被调用  第一步需要拿到已经选中的元素

//得到不同组合的算法函数
import { bwPowerSet } from "@/utils/constfun.js"
export default {
  name: "GoodsSku",
  props: ["specs", "skus"],
  data() {
      return {
          list: [], //长度和specs的长度是一样的
          yes: true,//控制watch中函数只执行一次
      };
  },
  methods: {
      //实现规格的单一选中
      //思路：如果选中就给当前行的当前值加一个属性selected  为true
      select(key, k) {
          // 取消选择
          if (this.list[key].values[k].selected) {
              this.list[key].values[k].selected = !this.list[key].values[k].selected
              return false
          }
          //this.list[key].values[k].selected=true
          //先将每一个大行变为false
          this.list[key].values.forEach((item, index) => {
              this.$set(this.list[key].values[index], "selected", false);
          })
          //让当前的变为true
          this.$set(this.list[key].values[k], "selected", true);
          //检查剩下的路径
          this.checkMap()
          // 怎么才能已经选完了呢
          var arr = this.getSelectArr().filter(it => it)
          const mapdata = this.getDataMap()
          if (arr.length == this.list.length) {
              // 组合父组件要使用的数据
              var obj = {}
              // 将路径拼成字符串
              var path = arr.join("*")
              // 根据路径从字典中拿到id
              var skuid = mapdata[path][0]
              // 根据id找到想要的数据
              var skuobj = this.skus.find(item => item.id == skuid)
              obj.skuid = skuobj.id
              obj.inventory = skuobj.inventory
              obj.price = skuobj.price
              obj.oldPrice = skuobj.oldPrice
              var str = ''
              skuobj.specs.forEach(item => {
                  str += item.name + ":" + item.valueName + ""
              })
              obj.skuname = str
              this.$emit("send", obj)
          }
      },
      //得到不同的有效组合
      getDataMap() {
          let objmap = {}
          this.skus.forEach(item => {
              //1首先是得有库存
              if (item.inventory > 0) {
                  //得到有效的属性组合
                  const arr = item.specs.map(it => it.valueName)
                  //得到所有子集
                  const allArr = bwPowerSet(arr)
                  //如果子集中是数组 我们可以约定用*连接一下，目的就是让多个数组的元素变成字符串好判断
                  //定义一个对象 
                  allArr.forEach(it => {
                      var newname = it.join("*")
                      if (objmap[newname]) {
                          //在数组中存在
                          objmap[newname].push(item.id)
                      } else {
                          //不存在
                          objmap[newname] = [item.id]
                      }
                  })
              }
          })
          return objmap
      },
      //检查路径是否有禁用的按钮  点击的时候会被调用
      checkMap() {
          //拿到有效路径
          var objmap = this.getDataMap()
          //遍历所有的specs 然后已经选择就忽略  没有选择的拿到当前的undefined的位置进行比对看看是否为有效的路径
          this.list.forEach((item, key) => {
              //需要拿到已经选中元素的数组 
              var selectArr = this.getSelectArr()
              item.values.forEach(it => {
                  //怎么知道it
                  if (selectArr.includes(it.name)) return false
                  //如果不存在让后面遍历的数据替换undefined
                  selectArr[key] = it.name
                  //将数组元素连城路径
                  var path = selectArr.filter(v => v).join("*")
                  //将路径path拿到有效路径中去判断是否存在 然后再决定是否禁用
                  if (objmap[path]) {
                      it.disabled = false
                  } else {
                      it.disabled = true
                  }
              })
          })
      },
      //已经选中元素的数组  结构[] 元素的个数和specs的长度是一样的   怎么知道哪个元素被选中了呢
      getSelectArr() {
          var arr = []
          this.specs.forEach((item, key) => {
              var obj = item.values.find(it => { return it.selected })
              arr[key] = obj ? obj.name : undefined
          })
          return arr
      }
  },
  watch: {
      specs: {
          handler() {
              if (this.yes) {
                  var mapobj = this.getDataMap()
                  this.list = this.specs
                  //处理一下this.list  让每一个属性都在有效路径的对象中过一遍，同时添加disabled属性，在有效字典的添加true 否则添加false即可
                  this.list.forEach(item => {
                      item.values.forEach(it => {
                          //能在数据字典中找到名字的 不禁用  false
                          if (mapobj[it.name]) {
                              it.disabled = false
                          } else {
                              //找不到的就禁用
                              it.disabled = true
                          }
                      })
                  })
                  this.yes = false
              }
          },
          deep: true
      }
  }
};
</script>
<style scoped lang="scss">
@import "../../assets/css/variables.scss";

@mixin sku-state-mixin {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;

  &.selected {
      border-color: $xtxColor;
  }

  &.disabled {
      opacity: 0.6;
      border-style: dashed;
      cursor: not-allowed;
  }
}

.goods-sku {
  padding-left: 10px;
  padding-top: 20px;

  dl {
      display: flex;
      padding-bottom: 20px;
      align-items: center;

      dt {
          width: 50px;
          color: #999;
      }

      dd {
          flex: 1;
          color: #666;

          >img {
              width: 50px;
              height: 50px;
              @include sku-state-mixin;
          }

          >span {
              display: inline-block;
              height: 30px;
              line-height: 28px;
              padding: 0 20px;
              @include sku-state-mixin;
          }
      }
  }
}
</style>
